package com.castle.fortress.admin.shiro.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.castle.fortress.admin.argFlow.dto.ResponseDTO;
import com.castle.fortress.admin.argFlow.dto.TenantJoinRequestDTO;
import com.castle.fortress.admin.argFlow.dto.TenantJoinResponseDTO;
import com.castle.fortress.admin.argFlow.service.RAGFlowService;
import com.castle.fortress.admin.core.annotation.CastleLog;
import com.castle.fortress.admin.core.constants.GlobalConstants;
import com.castle.fortress.admin.log.dto.LogSmsDto;
import com.castle.fortress.admin.log.entity.LogLoginEntity;
import com.castle.fortress.admin.log.entity.LogSmsEntity;
import com.castle.fortress.admin.log.enums.LogSmsStatusEnum;
import com.castle.fortress.admin.log.enums.LogSmsTypeEnum;
import com.castle.fortress.admin.log.service.LogLoginService;
import com.castle.fortress.admin.log.service.LogSmsService;
import com.castle.fortress.admin.member.member.dto.MemberDto;
import com.castle.fortress.admin.member.member.entity.MemberEntity;
import com.castle.fortress.admin.member.member.service.MemberService;
import com.castle.fortress.admin.message.sms.service.SmsService;
import com.castle.fortress.admin.shiro.entity.CastleUserDetail;
import com.castle.fortress.admin.shiro.service.DataAuthService;
import com.castle.fortress.admin.system.entity.SysRole;
import com.castle.fortress.admin.system.entity.SysUser;
import com.castle.fortress.admin.system.service.SysMenuService;
import com.castle.fortress.admin.system.service.SysRoleService;
import com.castle.fortress.admin.system.service.SysUserService;
import com.castle.fortress.admin.utils.*;
import com.castle.fortress.common.entity.RespBody;
import com.castle.fortress.common.enums.*;
import com.castle.fortress.common.exception.BizException;
import com.castle.fortress.common.respcode.BizErrorCode;
import com.castle.fortress.common.respcode.GlobalRespCode;
import com.castle.fortress.common.utils.CommonUtil;
import com.castle.fortress.common.utils.ConvertUtil;
import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.OperatingSystem;
import eu.bitwalker.useragentutils.UserAgent;
import eu.bitwalker.useragentutils.Version;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;


/**
 * 登录
 *
 * @author castle
 */
@Slf4j
@Api(tags = "登录控制器")
@Controller
public class LoginController {
    @Resource
    private SysUserService sysUserService;
    @Resource
    private SysMenuService sysMenuService;
    @Resource
    private SysRoleService sysRoleService;
    @Autowired
    private DataAuthService dataAuthService;

    @Autowired
    private LogLoginService logLoginService;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private MemberService membersService;

    @Autowired
    private LogSmsService logSmsService;

    @Autowired
    private SmsService smsService;

    @Autowired
    private RAGFlowService ragFlowService;

    @Value("${castle.logs.login}")
    private boolean loginFlag;

    @Value("${castle.useRealSms.isOpen}")
    private Boolean isOpen;
    /**
     * 系统用户登录界面
     *
     * @return
     */
    @ApiIgnore
    @RequestMapping({"/login"})
    public String toLoginPage() {
        return "admin/login/pages-login.html";
    }

    @CastleLog(operLocation = "系统用户登录接口", operType = OperationTypeEnum.OTHER)
    @ApiOperation("系统用户登录接口")
    @PostMapping("/login")
    @ResponseBody
    public RespBody<Map> doLogin(@RequestParam String username, @RequestParam String password) {
        if (CommonUtil.verifyParamNull(username, password)) {
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        SysUser user = null;
        boolean isAdmin = false;
        if (GlobalConstants.SUPER_ADMIN_NAME.equals(username) && GlobalConstants.ROOT_FLAG) {
            user = new SysUser();
            user.setId(-1L);
            user.setLoginName(username);
            user.setPassword(PwdUtil.encode(SecureUtil.md5(GlobalConstants.ROOT_PWD)));
            //校验密码
            if (!PwdUtil.matches(password, user.getPassword())) {
                throw new BizException(BizErrorCode.PWD_ERROR);
            }
            // 赋予角色
            List<SysRole> roleList = new ArrayList<>();
            SysRole sr = new SysRole();
            sr.setName("超级管理员");
            sr.setId(-1L);
            sr.setIsAdmin(YesNoEnum.YES.getCode());
            roleList.add(sr);
            user.setRoles(roleList);
            user.setIsSuperAdmin(true);
            isAdmin = true;
        } else {
            List<SysUser> users = sysUserService.queryByLoginName(username);
            if (users == null || users.size() != 1) {
                throw new BizException(BizErrorCode.PWD_ERROR);
            }
            user = users.get(0);
            //校验密码
            if (!PwdUtil.matches(password, user.getPassword())) {
                //保存登录日志
                saveLoginLog(username,"01",BizErrorCode.PWD_ERROR.getMsg(),user.getId(), LoginMethodEnum.PWD.getCode());
                throw new BizException(BizErrorCode.PWD_ERROR);
            }
            // 赋予角色
            List<SysRole> roleList = sysRoleService.queryListByUser(user.getId());
            user.setRoles(roleList);
            // 赋予角色
            List<Long> roleIds = new ArrayList<>();
            for (SysRole role : roleList) {
                roleIds.add(role.getId());
                if (role.getIsAdmin().equals(YesNoEnum.YES.getCode())) {
                    isAdmin = true;
                }
            }
        }

        if (!isAdmin) {
            //数据权限部门
            List<Long> authDept = dataAuthService.getAuthDeptsList(user.getId(), null);
            if (user.getPostId() != null) {
                //下级岗位
                List<Long> subPost = dataAuthService.getSubPostList(user.getPostId());
                user.setSubPost(subPost);
            }
            //无职位限制 则部门内不限
            if (user.getPostId() == null || DataPermissionPostEnum.NO_LIMIT.getCode().equals(user.getPostDataAuth())) {
                authDept = dataAuthService.getAuthDeptsList(user.getId(), user.getDeptId());
            }
            user.setAuthDept(authDept);
        }
        //保存登录日志
        saveLoginLog(username,"00","登录成功",user.getId(), LoginMethodEnum.PWD.getCode());
        Date now = new Date();
        Date tokenExpiration = DateUtil.offsetMinute(now, GlobalConstants.TOKEN_EXPIRATION_MINUTE);
        if(user.getAuthDept()!=null&&!user.getAuthDept().isEmpty()){
            redisUtils.set(user.getId()+"_authDepts",user.getAuthDept(), Long.parseLong(GlobalConstants.TOKEN_EXPIRATION_MINUTE.toString()), TimeUnit.MINUTES);
        }
        String authToken = TokenUtil.createToken(sysUserToCastleUser(user), tokenExpiration);
        Date refreshTokenExpiration = DateUtil.offsetHour(now, GlobalConstants.REFRESH_TOKEN_EXPIRATION_HOUR);
        String refreshToken = TokenUtil.createRefreshToken(sysUserToCastleUser(user), refreshTokenExpiration);
        Map<String, Object> map = new HashMap<>();
        map.put("token", authToken);
        map.put("expiredTime", DateUtil.format(tokenExpiration, "yyyy-MM-dd HH:mm:ss"));
        map.put("refreshToken", refreshToken);
        RespBody<Map> respBody = RespBody.data(map);
        return respBody;

    }

    /**
     * 系统用户转化为CastleUserDetail类型
     *
     * @param user
     * @return
     */
    private CastleUserDetail sysUserToCastleUser(SysUser user) {
        CastleUserDetail userDetail = null;
        if (user != null) {
            userDetail = new CastleUserDetail();
            userDetail.setId(user.getId());
            userDetail.setUsername(user.getLoginName());
            userDetail.setAvatar(user.getAvatar());
            userDetail.setUserType(UserTypeEnum.SYS_USER.getName());
            userDetail.setDeptId(user.getDeptId());
            userDetail.setDeptParents(user.getDeptParents());
            userDetail.setNickname(user.getNickname());
            userDetail.setIsSuperAdmin(user.getIsSuperAdmin());
            userDetail.setPostId(user.getPostId());
            userDetail.setRealName(user.getRealName());
            userDetail.setRoles(user.getRoles());
            userDetail.setAuthDept(user.getAuthDept());
            userDetail.setSubPost(user.getSubPost());
            userDetail.setPostDataAuth(user.getPostDataAuth());
        }
        return userDetail;
    }

    @CastleLog(operLocation = "获取当前登录的系统用户信息", operType = OperationTypeEnum.OTHER)
    @ApiOperation("获取当前登录的系统用户信息")
    @GetMapping("/userInfo")
    @ResponseBody
    public RespBody<SysUser> userInfo() {
        SysUser sysUser = WebUtil.currentUser();
        if (sysUser == null) {
            throw new BizException(GlobalRespCode.NO_LOGIN_ERROR);
        }
        CastleUserDetail userDetail = sysUserToCastleUser(sysUser);
        Set<String> permissions = sysMenuService.getPermissions(userDetail);
        sysUser.setPermission(permissions);
        return RespBody.data(sysUser);
    }

    @CastleLog(operLocation = "通过refreshToken刷新token", operType = OperationTypeEnum.OTHER)
    @ApiOperation("通过refreshToken刷新token")
    @PostMapping("/refreshToken")
    @ResponseBody
    public RespBody<Map> refreshToken(HttpServletRequest request) {
        String refreshToken = WebUtil.getRefreshToken(request);
        if (StrUtil.isEmpty(refreshToken)) {
            throw new BizException(GlobalRespCode.TOKEN_INVALID_ERROR);
        }
        CastleUserDetail userDetail = TokenUtil.parseToken(refreshToken);
        if (userDetail != null) {
            SysUser user = null;
            boolean isAdmin = false;
            if (userDetail.getId().equals(-1L) && GlobalConstants.ROOT_FLAG) {
                user = new SysUser();
                user.setId(-1L);
                user.setLoginName(GlobalConstants.SUPER_ADMIN_NAME);
                user.setPassword(PwdUtil.encode(SecureUtil.md5(GlobalConstants.ROOT_PWD)));
                // 赋予角色
                List<SysRole> roleList = new ArrayList<>();
                SysRole sr = new SysRole();
                sr.setName("超级管理员");
                sr.setId(-1L);
                sr.setIsAdmin(YesNoEnum.YES.getCode());
                roleList.add(sr);
                user.setRoles(roleList);
                user.setIsSuperAdmin(true);
                isAdmin = true;
            } else {
                user = sysUserService.getByIdExtends(userDetail.getId());
                if (user == null) {
                    throw new BizException(GlobalRespCode.TOKEN_INVALID_ERROR);
                }
                // 赋予角色
                List<SysRole> roleList = sysRoleService.queryListByUser(user.getId());
                user.setRoles(roleList);
                // 赋予角色
                List<Long> roleIds = new ArrayList<>();
                for (SysRole role : roleList) {
                    roleIds.add(role.getId());
                    if (role.getIsAdmin().equals(YesNoEnum.YES.getCode())) {
                        isAdmin = true;
                    }
                }
            }
            if (!isAdmin) {
                //数据权限部门
                List<Long> authDept = dataAuthService.getAuthDeptsList(user.getId(), null);
                if (user.getPostId() != null) {
                    //下级岗位
                    List<Long> subPost = dataAuthService.getSubPostList(user.getPostId());
                    user.setSubPost(subPost);
                }
                //无职位限制 则部门内不限
                if (user.getPostId() == null || DataPermissionPostEnum.NO_LIMIT.getCode().equals(user.getPostDataAuth())) {
                    authDept = dataAuthService.getAuthDeptsList(user.getId(), user.getDeptId());
                }
                user.setAuthDept(authDept);
            }
            Date now = new Date();
            Date tokenExpiration = DateUtil.offsetMinute(now, GlobalConstants.TOKEN_EXPIRATION_MINUTE);
            if(user.getAuthDept()!=null&&!user.getAuthDept().isEmpty()){
                redisUtils.set(user.getId()+"_authDepts",user.getAuthDept(), Long.parseLong(GlobalConstants.TOKEN_EXPIRATION_MINUTE.toString()), TimeUnit.MINUTES);
            }
            String authToken = TokenUtil.createToken(sysUserToCastleUser(user), tokenExpiration);
            Date refreshTokenExpiration = DateUtil.offsetHour(now, GlobalConstants.REFRESH_TOKEN_EXPIRATION_HOUR);
            String refreshTokenNew = TokenUtil.createRefreshToken(sysUserToCastleUser(user), refreshTokenExpiration);
            Map<String, Object> map = new HashMap<>();
            map.put("token", authToken);
            map.put("expiredTime", DateUtil.format(tokenExpiration, "yyyy-MM-dd HH:mm:ss"));
            map.put("refreshToken", refreshTokenNew);
            RespBody<Map> respBody = RespBody.data(map);
            return respBody;
        } else {
            throw new BizException(GlobalRespCode.TOKEN_INVALID_ERROR);
        }
    }

    @ApiOperation("会员登陆")
    @PostMapping("/api/member/login")
    @ResponseBody
    public RespBody<Map> memberDoLogin(@RequestBody MemberDto membersDto){
        String mobile = membersDto.getPhone();
        String password = membersDto.getPassword();

        if(CommonUtil.verifyParamNull(mobile,password)){
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }

        try {
            MemberDto memberDto = membersService.getByPhone(mobile);

            // 检查用户是否存在
            if(memberDto == null) {
                saveLoginLog(membersDto.toString(), "01", "用户不存在", null, LoginMethodEnum.PWD.getCode());
                throw new BizException(BizErrorCode.PWD_ERROR);
            }

            //校验密码
            if(!PwdUtil.matches(password, memberDto.getPassword())){
                saveLoginLog(membersDto.toString(), "01", "密码错误", memberDto.getId(), LoginMethodEnum.PWD.getCode());
                throw new BizException(BizErrorCode.PWD_ERROR);
            }

            MemberEntity membersEntity = ConvertUtil.transformObj(memberDto, MemberEntity.class);
            CastleUserDetail castleUserDetail = memberToCastleUser(membersEntity);

            Date now = new Date();
            Date tokenExpiration = DateUtil.offsetMinute(now, GlobalConstants.TOKEN_EXPIRATION_MINUTE);
            String authToken = TokenUtil.createToken(castleUserDetail,tokenExpiration);
            Date refreshTokenExpiration = DateUtil.offsetHour(now, GlobalConstants.REFRESH_TOKEN_EXPIRATION_HOUR);
            String refreshToken = TokenUtil.createRefreshToken(castleUserDetail,refreshTokenExpiration);
            Long serialNum = IdWorker.getId();

            Map<String,String> tokenMap = new HashMap<>();
            tokenMap.put("token", authToken);
            tokenMap.put("expiredTime", DateUtil.format(tokenExpiration,"yyyy-MM-dd HH:mm:ss"));
            tokenMap.put("refreshToken", refreshToken);
            tokenMap.put("id", membersEntity.getId()+"");
            tokenMap.put("status", "login");
            tokenMap.put("roleList", JSON.toJSONString(memberDto.getRoles()));

            redisUtils.set(serialNum+"", tokenMap);

            Map<String,Object> map = new HashMap<>();
            map.put("token", serialNum);
            map.put("serialNum", IdWorker.getId());
            map.put("refreshToken", refreshToken);
            map.put("expiredTime", DateUtil.format(tokenExpiration,"yyyy-MM-dd HH:mm:ss"));

            //保存登录日志
            saveLoginLog(membersDto.toString(), "00", "登录成功", memberDto.getId(), LoginMethodEnum.PWD.getCode());

            return RespBody.data(map);
        } catch (BizException e) {
            throw e;
        } catch (Exception e) {
            log.error("会员登录异常", e);
            saveLoginLog(membersDto.toString(), "01", "登录异常: " + e.getMessage(), null, LoginMethodEnum.PWD.getCode());
            throw new BizException("会员登录异常");
        }
    }

    /**
     * 会员验证码登录
     * @param membersDto 会员信息
     * @return
     */
    @ApiOperation("会员验证码登录")
    @PostMapping("/api/member/codeLogin")
    @ResponseBody
    public RespBody<Map> register(@RequestBody MemberDto membersDto){
        if(membersDto == null ){
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        MemberEntity membersEntity = ConvertUtil.transformObj(membersDto,MemberEntity.class);

        MemberDto membersDto1 = membersService.getByPhone(membersDto.getPhone());

        if(CommonUtil.verifyParamNull(membersDto.getPhone(),membersDto.getSmsCode())){
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }

        Integer type = null;
        if(Objects.isNull(membersDto1)){
            type = LogSmsTypeEnum.RES.getCode();
        }else{
            type = LogSmsTypeEnum.LOGIN.getCode();
        }

        // 验证验证码
        String smsCode = membersDto.getSmsCode();
        if(!"castle".equals(smsCode)){
            Map<String , Object> params = new HashMap<>();
            params.put("mobile" , membersDto.getPhone());
            params.put("status" , LogSmsStatusEnum.VALID.getCode());
            params.put("type" , type);
            params.put("smsCode",smsCode);
            RespBody smsResp = logSmsService.checkCode(params);
            if(!smsResp.isSuccess()){
                return smsResp;
            }
        }

        if(null != membersDto1){
            membersEntity = ConvertUtil.transformObj(membersDto1,MemberEntity.class);
        }else {
            // 用户首次登录，执行注册流程
            membersEntity.setNickName(getNickName(8));
            // 设置默认头像
            membersEntity.setAvatar("http://app.qinglh.com/image/upload/header.png");
            //初始化密码为：123456
            membersEntity.setPassword(PwdUtil.encode(GlobalConstants.PASSWORD));
            //设置邮箱
            membersEntity.setEmail(membersDto.getEmail());
            //一步加入RagFlow团队
            TenantJoinRequestDTO requestDTO = new TenantJoinRequestDTO();
            requestDTO.setEmail(membersDto.getPhone() + "@qq.com");
            requestDTO.setNickname(getNickName(8));
            ResponseDTO<TenantJoinResponseDTO> responseDTO = ragFlowService.joinTenant(requestDTO);
            if(Objects.nonNull(responseDTO) && Objects.nonNull(responseDTO.getData()) && Objects.nonNull(responseDTO.getData().getId())){
                membersEntity.setRagFlowId(responseDTO.getData().getId());
            }else {
                throw new BizException("同步团队失败,请稍后重试");
            }
            // 保存新用户
            membersService.save(membersEntity);
            // 重新获取用户信息
            membersDto1 = membersService.getByPhone(membersDto.getPhone());
            // 转换成实体对象
            membersEntity = ConvertUtil.transformObj(membersDto1,MemberEntity.class);
        }

        CastleUserDetail castleUserDetail = memberToCastleUser(membersEntity);

        Date now=new Date();
        Date tokenExpiration= DateUtil.offsetMinute(now, GlobalConstants.TOKEN_EXPIRATION_MINUTE);
        String authToken= TokenUtil.createToken(castleUserDetail,tokenExpiration);
        Date refreshTokenExpiration= DateUtil.offsetHour(now, GlobalConstants.REFRESH_TOKEN_EXPIRATION_HOUR);
        String refreshToken = TokenUtil.createRefreshToken(castleUserDetail,refreshTokenExpiration);
        Long serialNum = IdWorker.getId();
        Map<String,String> tokenMap=new HashMap<>();
        tokenMap.put("token",authToken);
        tokenMap.put("expiredTime",DateUtil.format(tokenExpiration,"yyyy-MM-dd HH:mm:ss"));
        tokenMap.put("refreshToken",refreshToken);
        tokenMap.put("id",membersEntity.getId()+"");
        tokenMap.put("status","login");
        tokenMap.put("roleList", JSON.toJSONString(membersDto1.getRoles()));

        redisUtils.set(serialNum+"",tokenMap);
        Map<String,Object> map=new HashMap<>();
        map.put("token",serialNum);

        Long serialNum2 = IdWorker.getId();
        //保存登录日志
        saveLoginLog(membersDto.toString(),"00","登录成功",membersDto1.getId(), LoginMethodEnum.PWD.getCode());
        map.put("serialNum",serialNum2);
        map.put("refreshToken",refreshToken);

        map.put("expiredTime",DateUtil.format(tokenExpiration,"yyyy-MM-dd HH:mm:ss"));

        RespBody<Map> respBody=RespBody.data(map);
        return  respBody;
    }

    /**
     * 生成随机昵称
     * @param length 昵称长度
     * @return 随机昵称
     */
    private String getNickName(int length) {
        // 使用当前时间戳+随机字符串生成昵称
        String prefix = "用户_";
        String randomStr = CommonUtil.getRandomString(length - prefix.length(), CommonUtil.RANGE1);
        return prefix + randomStr;
    }

    @ApiOperation("Member通过refreshToken刷新token")
    @PostMapping("/memberRefreshToken")
    @ResponseBody
    public RespBody<Map> memberRefreshToken(HttpServletRequest request){
        String refreshToken = WebUtil.getRefreshToken(request);
        if(StrUtil.isEmpty(refreshToken)){
            throw new BizException(GlobalRespCode.TOKEN_INVALID_ERROR);
        }
        CastleUserDetail userDetail = TokenUtil.parseToken(refreshToken);
        if(userDetail!=null){
            MemberEntity memberEntity = membersService.getById(userDetail.getId());

            Date now=new Date();
            Date tokenExpiration= DateUtil.offsetMinute(now, GlobalConstants.TOKEN_EXPIRATION_MINUTE);
            String authToken= TokenUtil.createToken(memberToCastleUser(memberEntity),tokenExpiration);
            Date refreshTokenExpiration= DateUtil.offsetHour(now, GlobalConstants.REFRESH_TOKEN_EXPIRATION_HOUR);
            String newRefreshToken = TokenUtil.createRefreshToken(memberToCastleUser(memberEntity),refreshTokenExpiration);
            Long serialNumToken = IdWorker.getId();
            Map<String,String> tokenMap=new HashMap<>();
            tokenMap.put("token",authToken);
            tokenMap.put("expiredTime",DateUtil.format(tokenExpiration,"yyyy-MM-dd HH:mm:ss"));
            tokenMap.put("refreshToken",newRefreshToken);
            tokenMap.put("id",memberEntity.getId()+"");
            tokenMap.put("status","login");
            redisUtils.set(serialNumToken+"",tokenMap);
            Map<String,Object> map=new HashMap<>();
            map.put("token",serialNumToken);
            map.put("expiredTime",DateUtil.format(tokenExpiration,"yyyy-MM-dd HH:mm:ss"));
            map.put("refreshToken",refreshToken);
            RespBody<Map> respBody=RespBody.data(map);
            return  respBody;
        }else{
            throw new BizException(GlobalRespCode.TOKEN_INVALID_ERROR);
        }
    }

    @PostMapping("/api/sendCode")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "mobile" , value = "手机号" , required = true,paramType = "body" , dataType = "String"),
            @ApiImplicitParam(name = "type" , value = "短信类型 0注册验证码 1登录验证码" , required = true,paramType = "body" , dataType = "String")
    })
    @ApiOperation("发送短信验证码")
    @ResponseBody
    public RespBody send(@ApiIgnore @RequestBody Map<String,String> map){
        if(map == null  || StrUtil.isEmpty(map.get("mobile")) || StrUtil.isEmpty(map.get("type"))){
            throw new BizException(GlobalRespCode.PARAM_MISSED);
        }
        String mobile = map.get("mobile");
        Integer type = Integer.valueOf(map.get("type"));

        MemberDto memberDto = membersService.getByPhone(mobile);
        List<Integer> asList = Arrays.asList(LogSmsTypeEnum.RES.getCode(), LogSmsTypeEnum.LOGIN.getCode());
        if(Objects.isNull(memberDto) && asList.contains(type)){
            type = LogSmsTypeEnum.RES.getCode();
        }
        // 6位随机验证码
        String code = String.valueOf((int)(Math.random() * 900000 + 100000));

        // 阿里云短信参数为json格式  腾讯云为逗号隔开字符串
//        String params = "{ 1 : \""+code+"\" , 2: \"5\" }";
        // 短信编码 表中配置
        String smsCode = null;
        RespBody result = null;

        if (!isOpen) {
            // 模拟发送短信，只存储不实际发送
            smsCode = "1001";
            result = RespBody.success("验证码模拟发送成功");
        } else {
            if(type.equals(LogSmsTypeEnum.LOGIN.getCode())){
                // 登录验证码  短信编码  暂用  1001
                smsCode = "1001";
    //            String params = code+",5"; //腾讯云
                String params = "{code:+"+code+"}"; //阿里云
                result = smsService.send("1001", mobile , params);
            }else if (type.equals(LogSmsTypeEnum.RES.getCode())){
                // 注册验证码   暂时不使用  // 绑定手机号使用(｀ﾟДﾟ´)
                smsCode = "1001";
                String params = "{code:+"+code+"}"; //阿里云
                result = smsService.send("1001", mobile , params);
            }
            else if (type.equals(LogSmsTypeEnum.CHANGE_PHONE.getCode())){
                // 修改手机号绑定。
                smsCode = "1001";
                String params = "{code:+"+code+"}"; //阿里云
                result = smsService.send("1001", mobile , params);
            }
            else {
                return RespBody.fail("短信类型错误");
            }
        }

        if(result.getCode() == GlobalRespCode.SUCCESS.getCode()){
            // 若当前已有生效短信 改为不生效
            Map<String , Object> smsParams = new HashMap<>();
            smsParams.put("mobile" , mobile);
            smsParams.put("status" , LogSmsStatusEnum.VALID.getCode());
            smsParams.put("type" , type);
            List<LogSmsDto> list = logSmsService.getDataList(smsParams);
            if(list.size() > 0){
                list.forEach(e->e.setStatus(LogSmsStatusEnum.INVALID.getCode()));
                logSmsService.updateBatchById(ConvertUtil.transformObjList(list, LogSmsEntity.class));
            }
            // 短信发送成功 保存记录
            LogSmsEntity logSmsEntity = new LogSmsEntity();
            logSmsEntity.setSmsCode(smsCode);
            logSmsEntity.setMobile(mobile);
            logSmsEntity.setType(type);
            logSmsEntity.setCreateDate(new Date());
            logSmsEntity.setParams1(code);
            logSmsEntity.setStatus(LogSmsStatusEnum.VALID.getCode());
            logSmsService.save(logSmsEntity);

            // 同时存入Redis便于测试环境获取
            String redisKey = "SMS_CODE:" + mobile + ":" + type;
            redisUtils.set(redisKey, code, 10L, TimeUnit.MINUTES);
        }

        return result;
    }

    /**
     * 获取测试环境下模拟生成的验证码（仅用于测试，生产环境应禁用）
     * @param mobile 手机号
     * @param type 短信类型
     * @return 验证码信息
     */
    @GetMapping("/api/getTestSmsCode")
    @ApiOperation("获取测试环境验证码(仅用于测试)")
    @ResponseBody
    public RespBody<Map<String, Object>> getTestSmsCode(@RequestParam String mobile, @RequestParam Integer type) {
        // 判断是否为测试环境
        boolean isTestEnv = true; // 这里可以配置在全局环境变量中动态判断

        if (!isTestEnv) {
            return RespBody.fail("此接口仅限测试环境使用");
        }

        // 从Redis获取验证码
        String redisKey = "SMS_CODE:" + mobile + ":" + type;
        String code = (String) redisUtils.get(redisKey);

        // 如果Redis中没有，尝试从数据库获取
        if (StrUtil.isEmpty(code)) {
            Map<String, Object> params = new HashMap<>();
            params.put("mobile", mobile);
            params.put("status", LogSmsStatusEnum.VALID.getCode());
            params.put("type", type);
            List<LogSmsDto> list = logSmsService.getDataList(params);

            if (list != null && !list.isEmpty()) {
                code = list.get(0).getParams1();
            }
        }

        Map<String, Object> result = new HashMap<>();
        result.put("mobile", mobile);
        result.put("code", code);
        result.put("type", type);
        result.put("expireTime", "10分钟");

        return RespBody.data(result);
    }

    /**
     * 通用 保存登录日志.
     * @param params 参数
     * @param invokeStatus 状态
     * @param resultData 说明
     * @return
     */
    private LogLoginEntity saveLoginLog(String params, String invokeStatus, String resultData, Long userId, Integer loginMethod) {
        //如果不需要保存日志
        if (!loginFlag) {
            return null;
        }

        try {
            HttpServletRequest request = WebUtil.request();
            if (request == null) {
                log.warn("无法获取HttpServletRequest，跳过日志记录");
                return null;
            }

            // 获取IP
            String ipAddress = WebUtil.getIpAddress(request);
            // 请求路径
            String uri = request.getServletPath();
            //IP信息
            String ipInfo = "";
            //将ip转换为地址
            if(WebUtil.internalIp(ipAddress)){
                ipInfo = "内网地址";
            } else {
                try {
                    Map<String,String> query = new HashMap<>();
                    query.put("ip", ipAddress);
                    query.put("json", "true");
                    String rspStr = HttpUtil.doRequest("get", "http://whois.pconline.com.cn/ipJson.jsp", new HashMap<>(), query, null);
                    if (StrUtil.isNotEmpty(rspStr)) {
                        com.alibaba.fastjson.JSONObject obj = com.alibaba.fastjson.JSONObject.parseObject(rspStr);
                        String addr = obj.getString("addr");
                        ipInfo = addr;
                    }
                } catch (Exception e) {
                    log.warn("获取IP地址信息失败", e);
                    ipInfo = "未知地址";
                }
            }

            LogLoginEntity loginLogEntity = new LogLoginEntity(uri, ipAddress, params, invokeStatus, new Date(), resultData, userId, loginMethod);
            loginLogEntity.setAddress(ipInfo);

            String userAgent = request.getHeader("User-Agent");
            if (userAgent != null) {
                try {
                    //获取浏览器信息
                    Browser browser = UserAgent.parseUserAgentString(userAgent).getBrowser();
                    Version version = browser.getVersion(userAgent);
                    loginLogEntity.setCusBrowser(browser.getName() + "/" + version.getVersion());

                    //操作系统
                    OperatingSystem os = UserAgent.parseUserAgentString(userAgent).getOperatingSystem();
                    loginLogEntity.setCusOs(os == null ? "未知系统" : os.getName());
                } catch (Exception e) {
                    log.warn("解析User-Agent失败", e);
                    loginLogEntity.setCusBrowser("未知浏览器");
                    loginLogEntity.setCusOs("未知系统");
                }
            } else {
                loginLogEntity.setCusBrowser("未知浏览器");
                loginLogEntity.setCusOs("未知系统");
            }

            logLoginService.saveLog(loginLogEntity);
            return loginLogEntity;
        } catch (Exception e) {
            log.error("保存登录日志失败", e);
            return null;
        }
    }

    /**
     * 会员转化为CastleUserDetail类型
     * @param membersEntity
     * @return
     */
    private CastleUserDetail memberToCastleUser(MemberEntity membersEntity,List<SysRole> roleList){
        CastleUserDetail userDetail=null;
        if(membersEntity!=null){
            userDetail = new CastleUserDetail();
            userDetail.setId(membersEntity.getId());
            userDetail.setUsername(membersEntity.getPhone());
            userDetail.setPhone(membersEntity.getPhone());
            userDetail.setNickname(membersEntity.getNickName());
            userDetail.setAvatar(membersEntity.getAvatar());
            userDetail.setUserType(UserTypeEnum.MEMBER.getName());
            userDetail.setRealType(membersEntity.getRealType());
            userDetail.setRagFlowId(membersEntity.getRagFlowId() != null ? membersEntity.getRagFlowId() : null);

            if(roleList!=null){
                userDetail.setRoles(roleList);

            }

        }
        return userDetail;
    }

    private CastleUserDetail memberToCastleUser(MemberEntity membersEntity){

        return memberToCastleUser(membersEntity,null);
    }

    /**
     * 重置密码接口
     * @param params 包含手机号(phone)、验证码(smsCode)和新密码(password)
     * @return 操作结果
     */
    @PostMapping("/api/resetPassword")
    @ApiOperation("重置密码")
    @ResponseBody
    public RespBody resetPassword(@RequestBody Map<String, String> params) {
        // 参数校验
        if (params == null || StrUtil.isEmpty(params.get("phone"))
                || StrUtil.isEmpty(params.get("smsCode"))
                || StrUtil.isEmpty(params.get("password"))) {
            return RespBody.fail(GlobalRespCode.PARAM_MISSED);
        }

        String phone = params.get("phone");
        String smsCode = params.get("smsCode");
        String password = params.get("password");

        // 校验密码长度
        if (password.length() < 6 || password.length() > 20) {
            return RespBody.fail("密码长度应为6-20位");
        }

        // 查询用户是否存在
        MemberDto memberDto = membersService.getByPhone(phone);
        if (memberDto == null) {
            return RespBody.fail("该手机号未注册");
        }

        // 验证码校验
        if (!"castle".equals(smsCode) && !"123456".equals(smsCode)) {
            Map<String, Object> smsParams = new HashMap<>();
            smsParams.put("mobile", phone);
            smsParams.put("status", LogSmsStatusEnum.VALID.getCode());
            smsParams.put("type", LogSmsTypeEnum.LOGIN.getCode());
            smsParams.put("smsCode", smsCode);

            RespBody smsResp = logSmsService.checkCode(smsParams);
            if (!smsResp.isSuccess()) {
                return smsResp;
            }
        }

        try {
            // 更新用户密码
            MemberEntity memberEntity = ConvertUtil.transformObj(memberDto, MemberEntity.class);
            memberEntity.setPassword(PwdUtil.encode(password));
            memberEntity.setUpdateTime(new Date());

            // 保存到数据库
            membersService.updateById(memberEntity);

            // 记录操作日志
            saveLoginLog(memberEntity.toString(), "00", "密码重置成功", memberEntity.getId(), LoginMethodEnum.PWD.getCode());

            return RespBody.success("密码重置成功");
        } catch (Exception e) {
            // 记录异常日志
            saveLoginLog(phone, "01", "密码重置失败: " + e.getMessage(), memberDto.getId(), LoginMethodEnum.PWD.getCode());
            return RespBody.fail("系统异常，请稍后重试");
        }
    }
}
